/*
 * @brief:
 * @Author: TzzzT
 * @Date: 2022-09-24 13:46:12
 * @LastEditTime: 2023-05-02 18:52:05
 * @LastEditors: TzzzT
 */
#include "esp_system.h"
#include "driver/uart.h"
#include "esp_log.h"
#include "cJSON.h"
#include "string.h"

#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"

#include "RCS_protocol.h"
#include "RCS_net.h"
#include "RCS_ble_master.h"
#include "find_string.h"
#include "bc260.h"

static const char *NET_TAG = "N";
static const char *NET_REC_TAG = "NET_RX";

enum
{
    CHECK_SERVER_HEAD = 0,
    CHECK_SERVER_DATA = 1,
};

static net_rx_fifo_t net_rx_fifo = {
    .fifo = {0},
    .get_index = 0,
    .put_index = 0,
    .is_full = false,
};

static net_rx_pbuf_t *pbuf_alloc(uint16_t buffered_size)
{
    bool ret = false;
    net_rx_pbuf_t *p = calloc(1, sizeof(net_rx_pbuf_t) * 1);
    if (p != NULL)
    {
        p->message_buf = calloc(1, sizeof(uint8_t) * (buffered_size));
        if (p->message_buf != NULL)
        {
            p->message_size = buffered_size;
            ret = true;
        }
        else
        {
            free(p);
        }
    }
    if (ret)
    {
        return p;
    }
    else
    {
        return NULL;
    }
}

static void pbuf_free(net_rx_pbuf_t *p)
{
    if (p != NULL)
    {
        if (p->message_buf != NULL)
        {
            free(p->message_buf);
            p->message_buf = NULL;
        }
        else
        {
            ESP_LOGE(NET_TAG, "p->message_buf == null");
        }
        free(p);
    }
    else
    {
        ESP_LOGE(NET_TAG, "p == null");
    }
    p = NULL;
}

static void put_data_in_fifo(uint8_t *pack, uint16_t buffered_size)
{
    uint8_t put_index_temp = net_rx_fifo.put_index;
    if (++put_index_temp >= NET_RX_FIFO_DEPTH)
    {
        put_index_temp = 0;
    }
    if (put_index_temp == net_rx_fifo.get_index)
    {
        ESP_LOGE(NET_TAG, "rx fifo full");
        return;
    }
    net_rx_pbuf_t *p = pbuf_alloc(buffered_size);
    if (p != NULL)
    {
        memcpy(p->message_buf, pack, buffered_size);
    }
    net_rx_fifo.fifo[net_rx_fifo.put_index] = p;
    net_rx_fifo.put_index++;
    if (net_rx_fifo.put_index >= NET_RX_FIFO_DEPTH)
    {
        net_rx_fifo.put_index = 0;
    }
    return;
}

uint32_t net_server_message_num = 0;
static net_rx_pbuf_t *get_data_from_fifo(void)
{
    if (net_rx_fifo.get_index == net_rx_fifo.put_index)
    {
        ESP_LOGE(NET_TAG, "rx fifo empty");
        return NULL;
    }
    net_rx_pbuf_t *p = net_rx_fifo.fifo[net_rx_fifo.get_index];
    if (++(net_rx_fifo.get_index) >= NET_RX_FIFO_DEPTH)
    {
        net_rx_fifo.get_index = 0;
    }
    net_server_message_num++;
    ESP_LOGE(NET_TAG, "net_server_message_num: %" PRIu32 "", net_server_message_num);
    return p;
}

#define NET_RX_INFORM_Q_LENGTH NET_RX_FIFO_DEPTH

static QueueHandle_t net_inform_queue;

#define NET_RXBUF_SIZE 1024
#define NET_RXBUF_HEAD 8
typedef struct net_rx_block_s
{
    char wbtc_check_flag[5];
    uint32_t package_len;
    uint8_t package_buf[NET_RXBUF_SIZE];
    uint16_t cur_pack_idx;
    uint8_t head_buf[NET_RXBUF_HEAD];
    uint8_t cur_head_idx;
} net_rx_block_t;

static net_rx_block_t net_CB = {
    .wbtc_check_flag = "wbtc",
    .package_len = 0,
    .cur_pack_idx = 0,
    .package_buf = {0},
    .cur_head_idx = 0,
    .head_buf = {0},
};

extern TaskHandle_t heartbeatTaskHandle;

void unpack_head_buf(uint8_t *head, net_rx_block_t *CB)
{
    esp_log_buffer_hex("", head, 8);
    int i = 0;
    CB->package_len = 0;
    for (i = 0; i < 4; ++i)
    {
        CB->package_len |= (uint32_t)(head[i]) << (24 - 8 * i);
    }
    // ESP_LOGI("X", "CB->package_len:%d", CB->package_len);
}

void clear_netCB(net_rx_block_t *CB)
{
    CB->cur_head_idx = 0;
    CB->cur_pack_idx = 0;
    memset(CB->head_buf, 0, NET_RXBUF_HEAD);
    memset(CB->package_buf, 0, NET_RXBUF_SIZE);
}

/**
 * @brief
 * 服务器数据格式
 * 数据长度  | 和校验  | 数据
 * 4 字节    | 4 字节 | n 字节
 * 数据长度不包含和校验部分。
 * eg：
 * 数据为 0x01 0x01 0x01 0x01
 * 包： 0x00 0x00 0x00 0x04 0x00 0x00 0x00 0x04 0x01 0x01 0x01 0x01
 * @param raw_data
 * @param raw_len
 */
static uint8_t check_flag = CHECK_SERVER_HEAD;

void extract_data_to_server_message(uint8_t *raw_data, uint16_t raw_len)
{
    uint16_t left_len = raw_len;
    while (left_len > 0)
    {
        switch (check_flag)
        {
        case CHECK_SERVER_HEAD:
        {
            uint8_t need_head_len = NET_RXBUF_HEAD - net_CB.cur_head_idx;
            // ESP_LOGI("X", "need_head_len:%d", need_head_len);
            if (left_len >= need_head_len)
            {
                memcpy(net_CB.head_buf + net_CB.cur_head_idx, raw_data, need_head_len);
                // 解析头
                unpack_head_buf(net_CB.head_buf, &net_CB);
                left_len -= need_head_len;
                raw_data += need_head_len;
                check_flag = CHECK_SERVER_DATA;
            }
            else
            {
                // 不够一个头，保存起来。
                memcpy(net_CB.head_buf + net_CB.cur_head_idx, raw_data, left_len);
                net_CB.cur_head_idx += left_len;
                left_len = 0;
            }
            break;
        }
        case CHECK_SERVER_DATA:
        {
            uint32_t need_pack_len = net_CB.package_len - net_CB.cur_pack_idx;
            // ESP_LOGI("X", "need_pack_len:%d", need_pack_len);
            if (left_len >= need_pack_len)
            {
                uint32_t i = 0;
                for (i = 0; i < need_pack_len; ++i)
                {
                    net_CB.package_buf[net_CB.cur_pack_idx++] = raw_data[i];
                }
                if (net_CB.package_len != net_CB.cur_pack_idx)
                {
                    ESP_LOGE(NET_TAG, "error. package_len: %" PRIu32 " cur_pack_idx: %d", net_CB.package_len, net_CB.cur_pack_idx);
                }
                else
                {
                    // ESP_LOGE("net fifo", "put %d bytes into fifo", net_CB.package_len);
                    put_data_in_fifo(net_CB.package_buf, (uint16_t)net_CB.package_len);
                    uint8_t ret = 1;
                    xQueueSend(net_inform_queue, &ret, portMAX_DELAY);
                    check_flag = CHECK_SERVER_HEAD;
                }
                clear_netCB(&net_CB);
                left_len -= need_pack_len;
                raw_data += need_pack_len;
            }
            else
            {
                uint32_t i = 0;
                for (i = 0; i < left_len; ++i)
                {
                    net_CB.package_buf[net_CB.cur_pack_idx++] = raw_data[i];
                }
                left_len = 0;
            }
            break;
        }
        default:
            break;
        }
    }
}

extern rcs_mast_system_t rcsSystem;

static void net_up(uint8_t net_stat)
{
    rcsSystem.net.is_connected = true;
    ESP_LOGE(NET_REC_TAG, "server has open");
    if (eTaskGetState(heartbeatTaskHandle) == eSuspended)
    {
        ESP_LOGE(NET_REC_TAG, "vTaskResume( heartbeatTaskHandle )");
        vTaskResume(heartbeatTaskHandle);
    }
    if (rcsSystem.equip.pri_weapon.screen.is_hold)
    {
        uint16_t packagelen = 0;
        uint8_t *package = make_sync_data_package(&packagelen, (1 << NET_STATE_NOTIFY));
        rcs_send_to_bleserver(GUN_SCREEN_CLASS, package, packagelen);
        free(package);
    }
}

static void net_down(uint8_t net_stat)
{
    rcsSystem.net.is_connected = false;
    ESP_LOGE(NET_REC_TAG, "server close");
    if (rcsSystem.equip.pri_weapon.screen.is_hold)
    {
        uint16_t packagelen = 0;
        uint8_t *package = make_sync_data_package(&packagelen, (1 << NET_STATE_NOTIFY));
        rcs_send_to_bleserver(GUN_SCREEN_CLASS, package, packagelen);
        free(package);
    }
}
static void analyse_net_message(char *buf);

static void net_rx_thread(void *arg)
{
    BaseType_t xStatus;
    uint8_t ret;
    net_rx_pbuf_t *dummy_p;
    while (1)
    {
        xStatus = xQueueReceive(net_inform_queue, &ret, portMAX_DELAY);
        dummy_p = get_data_from_fifo();
        if (dummy_p == NULL)
        {
            continue;
        }
        // ESP_LOGI("NET RX", "get %d bytes from fifo", dummy_p->message_size);
        esp_log_buffer_char("NET RX", dummy_p->message_buf, dummy_p->message_size);
        analyse_net_message(dummy_p->message_buf);
        pbuf_free(dummy_p);
    }
}

void analyse_net_message(char *buf)
{
    ESP_LOGE(NET_REC_TAG, "start analyse json data");

    cJSON *jsMessage = cJSON_Parse(buf);
    if (jsMessage == NULL)
    {
        return;
    }
    cJSON *jsType = cJSON_GetObjectItem(jsMessage, "type");
    if (jsType == NULL)
    {
        return;
    }
    recei_from_server_data_type_t type = jsType->valueint;
    ESP_LOGE(NET_REC_TAG, "message type:%d", type);
    switch (type)
    {
    case START_NET_DOWN:
    {
        // 上传属性
        size_t message_length;
        char *message = make_net_json_package(RESPONSE_NET_UP, &message_length, NULL);
        if (message)
        {
            bc_send_package_to_server(message, message_length);
            free(message);
        }
        rcsSystem.net.start_heartbeat = true;
        break;
    }
    case MODIFY_PROPS_NET_DOWN:
    {
        rcsSystem.net.first_connect = false;
        cJSON *jsData = cJSON_GetObjectItem(jsMessage, "data");
        if (jsData == NULL)
        {
            return;
        }
        notify_mask_t notify_data_mask = 0;
        take_mutex();
        cJSON *jsTeamID = cJSON_GetObjectItem(jsData, "teamID");
        if (jsTeamID != NULL)
        {
            ESP_LOGI(NET_REC_TAG, "teamID:%d", jsTeamID->valueint);
            rcsSystem.game.player.team_id = jsTeamID->valueint;
        }
        cJSON *jsRoomID = cJSON_GetObjectItem(jsData, "roomID");
        if (jsRoomID != NULL)
        {
            ESP_LOGI(NET_REC_TAG, "roomID:%d", jsRoomID->valueint);
            rcsSystem.game.player.room_id = jsRoomID->valueint;
        }
        cJSON *jsGameID = cJSON_GetObjectItem(jsData, "gameId");
        if (jsGameID != NULL)
        {
            ESP_LOGI(NET_REC_TAG, "gameId:%d", jsGameID->valueint);
            rcsSystem.game.record_id = jsGameID->valueint;
        }
        cJSON *jsTeamIR = cJSON_GetObjectItem(jsData, "teamIR");
        if (jsTeamIR != NULL)
        {
            ESP_LOGI(NET_REC_TAG, "teamIR:%d", jsTeamIR->valueint);
            notify_data_mask |= change_player_team(jsTeamIR->valueint) << TEAM_NOTIFY;
        }
        cJSON *jsRoomIR = cJSON_GetObjectItem(jsData, "roomIR");
        if (jsRoomIR != NULL)
        {
            ESP_LOGI(NET_REC_TAG, "roomIR:%d", jsRoomIR->valueint);
            notify_data_mask |= change_player_room(jsRoomIR->valueint) << ROOM_NOTIFY;
        }
        cJSON *jsBulletNum = cJSON_GetObjectItem(jsData, "bullets");
        if (jsBulletNum != NULL)
        {
            ESP_LOGI(NET_REC_TAG, "bullets:%d", jsBulletNum->valueint);
            notify_data_mask |= change_player_bullet_nums(jsBulletNum->valueint) << BULLET_NUM_NOTIFY;
        }
        cJSON *jsDamage = cJSON_GetObjectItem(jsData, "atc");
        if (jsDamage != NULL)
        {
            ESP_LOGI(NET_REC_TAG, "atc:%d", jsDamage->valueint);
            bool res = change_player_damage(jsDamage->valueint);
            ESP_LOGI(NET_REC_TAG, "damage change:%d", res);
            notify_data_mask |= res << DAMAGE_NOTIFY;
        }
        cJSON *jsHp = cJSON_GetObjectItem(jsData, "hp");
        if (jsHp != NULL)
        {
            ESP_LOGI(NET_REC_TAG, "hp:%d", jsHp->valueint);
            notify_data_mask |= change_player_hp(jsHp->valueint) << HP_NOTIFY;
            notify_data_mask |= (1 << LIVING_NOTIFY);
        }
        cJSON *jsGameStatus = cJSON_GetObjectItem(jsData, "gamestatus");
        if (jsGameStatus != NULL)
        {
            ESP_LOGI(NET_REC_TAG, "gamestatus:%d", jsGameStatus->valueint);
            notify_data_mask |= change_game_state(jsGameStatus->valueint) << GAME_START_NOTIFY;
        }
        cJSON *jsDeath = cJSON_GetObjectItem(jsData, "death");
        if (jsDeath != NULL)
        {
            ESP_LOGI(NET_REC_TAG, "death:%d", jsDeath->valueint);
            notify_data_mask |= change_player_death(jsDeath->valueint) << DEATH_NOTIFY;
        }
        cJSON *jsKill = cJSON_GetObjectItem(jsData, "kill");
        if (jsKill != NULL)
        {
            ESP_LOGI(NET_REC_TAG, "kill:%d", jsKill->valueint);
            notify_data_mask |= change_player_kill(jsKill->valueint) << KILL_NOTIFY;
        }
        cJSON *jsTeamScore = cJSON_GetObjectItem(jsData, "teamScore");
        if (jsTeamScore != NULL)
        {
            ESP_LOGI(NET_REC_TAG, "teamScore:%d", jsTeamScore->valueint);
            notify_data_mask |= change_player_team_score(jsTeamScore->valueint) << TEAM_SCORE_NOTIFY;
        }
        cJSON *jsSignal = cJSON_GetObjectItem(jsData, "signal");
        if (jsSignal != NULL)
        {
            ESP_LOGI(NET_REC_TAG, "signal:%d", jsSignal->valueint);
            bool signal = jsSignal->valueint;
        }
        give_mutex();

        if (notify_data_mask != 0)
        {
            ESP_LOGE(NET_REC_TAG, "property changed, try to sync slave device");
            // 通知从机
            uint16_t packagelen;
            uint8_t *package = NULL;
            ESP_LOGI(NET_REC_TAG, "notify_data_mask:%" PRIu32 "", notify_data_mask);
            if (rcsSystem.equip.pri_weapon.point.is_hold)
            {
                package = make_sync_data_package(&packagelen, notify_data_mask & POINT_MASK_ARANGE);
                rcs_send_to_bleserver(GUN_POINT_CLASS, package, packagelen);
                free(package);
            }
            if (rcsSystem.equip.pri_weapon.screen.is_hold)
            {
                package = make_sync_data_package(&packagelen, notify_data_mask & SCREEN_MASK_ARANGE);
                rcs_send_to_bleserver(GUN_SCREEN_CLASS, package, packagelen);
                free(package);
            }
            if (rcsSystem.equip.armor.is_hold)
            {
                package = make_sync_data_package(&packagelen, notify_data_mask);
                rcs_send_to_bleserver(ARMOR_CLASS, package, packagelen);
                free(package);
            }
        }
        break;
    }
    case CONTROL_NET_DOWN:
    {
        cJSON *jsData = cJSON_GetObjectItem(jsMessage, "data");
        if (jsData == NULL)
        {
            return;
        }
        cJSON *jsOption = cJSON_GetObjectItem(jsData, "opt");
        uint8_t opt = jsOption->valueint;
        switch (opt)
        {
        case LED_OPEN:
        {
            ESP_LOGI(NET_REC_TAG, "LED_OPEN");
            break;
        }
        case LED_CLOSE:
        {
            ESP_LOGI(NET_REC_TAG, "LED_CLOSE");
            break;
        }
        case LED_TICKLE_FREQ_1:
        {
            ESP_LOGI(NET_REC_TAG, "LED_TICKLE_FREQ_1");
            break;
        }
        case LED_TICKLE_FREQ_2:
        {
            ESP_LOGI(NET_REC_TAG, "LED_TICKLE_FREQ_2");
            break;
        }
        case LED_TICKLE_CLOSE:
        {
            ESP_LOGI(NET_REC_TAG, "LED_TICKLE_CLOSE");
            break;
        }
        case MOTOR_OPEN:
        {
            ESP_LOGI(NET_REC_TAG, "MOTOR_OPEN");
            break;
        }
        case MOTOR_CLOSE:
        {
            ESP_LOGI(NET_REC_TAG, "MOTOR_CLOSE");
            break;
        }
        case MUSIC_SN:
        {
            ESP_LOGI(NET_REC_TAG, "MUSIC_SN");
            cJSON *jsContent = cJSON_GetObjectItem(jsData, "content");
            uint8_t music_number = jsOption->valueint;
            uint16_t packagelen;
            uint8_t *package = make_play_music_package(&packagelen, music_number);
            if (rcsSystem.equip.pri_weapon.screen.is_hold)
            {
                rcs_send_to_bleserver(GUN_SCREEN_CLASS, package, packagelen);
            }
            break;
        }
        case SCREEN_DATA:
        {
            ESP_LOGI(NET_REC_TAG, "SCREEN_DATA");
            cJSON *jsContent = cJSON_GetObjectItem(jsData, "content");
            char *content = jsOption->valuestring;
            uint16_t packagelen;
            uint8_t *package = make_hint_data_package(&packagelen, content);
            if (rcsSystem.equip.pri_weapon.screen.is_hold)
            {
                rcs_send_to_bleserver(GUN_SCREEN_CLASS, package, packagelen);
            }
            break;
        }
        default:
            break;
        }
        break;
    }
    case GAME_START_NET_DOWN:
    {
        notify_mask_t notify_data_mask = 0;
        cJSON *jsData = cJSON_GetObjectItem(jsMessage, "data");
        if (jsData == NULL)
        {
            return;
        }
        cJSON *jsGameStatus = cJSON_GetObjectItem(jsData, "gamestatus");
        if (jsGameStatus != NULL)
        {
            take_mutex();
            // ESP_LOGI(NET_REC_TAG, "game: %s", (jsGameStatus->valueint) ? "start" : "close");
            notify_data_mask |= change_game_state(jsGameStatus->valueint) << GAME_START_NOTIFY;
            if (!rcsSystem.game.start)
            {
                if (reset_player())
                {
                    notify_data_mask |= (1 << HP_NOTIFY) |
                                        (1 << TEAM_NOTIFY) |
                                        (1 << ROOM_NOTIFY) |
                                        (1 << DAMAGE_NOTIFY) |
                                        (1 << BULLET_NUM_NOTIFY);
                }
            }
            give_mutex();
        }
        if (notify_data_mask != 0)
        {
            // 通知从机
            //  ESP_LOGE(NET_REC_TAG, "changed, sync to slave device");
            uint16_t packagelen;
            uint8_t *package = make_sync_data_package(&packagelen, notify_data_mask);
            if (rcsSystem.equip.pri_weapon.point.is_hold)
            {
                rcs_send_to_bleserver(GUN_POINT_CLASS, package, packagelen);
            }
            if (rcsSystem.equip.pri_weapon.screen.is_hold)
            {
                rcs_send_to_bleserver(GUN_SCREEN_CLASS, package, packagelen);
            }
            if (rcsSystem.equip.armor.is_hold)
            {
                rcs_send_to_bleserver(ARMOR_CLASS, package, packagelen);
            }
            free(package);
        }
        break;
    }
    case HEARTBEAT_FEEDBACK_NET_DOWN:
    {
        break;
    }
    default:
        break;
    }
    if (type != HEARTBEAT_FEEDBACK_NET_DOWN)
    {
        set_game_event(REMOTE_COMM_EVENT, 4);
    }

    cJSON_Delete(jsMessage);
}

#define NET_RX_THR_PRI 17
void net_init(void)
{
    rcsSystem.net.first_connect = true;
    rcsSystem.net.is_connected = false;
    net_inform_queue = xQueueCreate(NET_RX_INFORM_Q_LENGTH, sizeof(uint8_t));
    bc260_init(extract_data_to_server_message, net_up, net_down);

    xTaskCreate(net_rx_thread, "net_rx_thread", 1024 * 10, NULL, NET_RX_THR_PRI, NULL);
}

static const char *NET_SEND_TAG = "NET_SEND";
// message在使用以后需要释放
char *make_net_json_package(send_to_server_data_type_t type, size_t *message_len, void *param[])
{
    cJSON *cjsonPtr = cJSON_CreateObject();
    cJSON_AddNumberToObject(cjsonPtr, "type", type);
    *message_len = 0;
    cJSON *dataObjPtr = cJSON_CreateObject();
    switch (type)
    {
    case RESPONSE_NET_UP:
    {
        // ESP_LOGI("json send", "dno :%d", rcsSystem.user.id);
        cJSON_AddNumberToObject(dataObjPtr, "dno", rcsSystem.user.id);
        cJSON_AddNumberToObject(dataObjPtr, "resetSymbol", !rcsSystem.net.first_connect);
        // ESP_LOGI("json send", "!rcsSystem.net.first_connect:%d", !rcsSystem.net.first_connect);
        if (!rcsSystem.net.first_connect)
        {
            cJSON_AddNumberToObject(dataObjPtr, "teamID", rcsSystem.game.player.team_id);
            cJSON_AddNumberToObject(dataObjPtr, "roomID", rcsSystem.game.player.room_id);
            cJSON_AddNumberToObject(dataObjPtr, "gameId", rcsSystem.game.record_id);
            cJSON_AddNumberToObject(dataObjPtr, "teamIR", rcsSystem.game.player.team);
            cJSON_AddNumberToObject(dataObjPtr, "roomIR", rcsSystem.game.player.room);
            cJSON_AddNumberToObject(dataObjPtr, "hp", rcsSystem.game.player.hp);
            cJSON_AddNumberToObject(dataObjPtr, "bullets", rcsSystem.game.player.bullet_nums);
            cJSON_AddNumberToObject(dataObjPtr, "atc", rcsSystem.game.player.damage);
            cJSON_AddNumberToObject(dataObjPtr, "death", (uint8_t)rcsSystem.game.start);
            cJSON *killersPtr = cJSON_CreateIntArray(rcsSystem.game.player.death_player, rcsSystem.game.player.death);
            cJSON_AddItemToObject(dataObjPtr, "killers", killersPtr);
        }
        break;
    }
    case HEARTBEAT_NET_UP:
    {
        int batt_arr[4] = {0};
        batt_arr[0] = rcsSystem.equip.core.battery;
        batt_arr[1] = rcsSystem.equip.armor.batt;
        batt_arr[2] = rcsSystem.equip.pri_weapon.point.batt;
        batt_arr[3] = rcsSystem.equip.pri_weapon.screen.batt;
        // ESP_LOGI(NET_SEND_TAG, "core:%d.armor:%d.point:%d.screen:%d.", batt_arr[0], batt_arr[1], batt_arr[2], batt_arr[3]);
        cJSON *battPtr = cJSON_CreateIntArray(batt_arr, 4);
        cJSON_AddItemToObject(dataObjPtr, "battery", battPtr);
        break;
    }
    case USE_BULLET_NET_UP:
    {
        cJSON_AddNumberToObject(dataObjPtr, "bullets", rcsSystem.game.player.bullet_nums);
        break;
    }
    case BE_HITTED_NET_UP:
    {
        cJSON_AddNumberToObject(dataObjPtr, "enemyDno", (const int32_t)param[0]);
        cJSON_AddNumberToObject(dataObjPtr, "hp", rcsSystem.game.player.hp);
        cJSON_AddNumberToObject(dataObjPtr, "damage", (const int32_t)param[1]);
        break;
    }
    case PROPPERTY_CHANGE_NET_UP:
    {
        cJSON_AddNumberToObject(dataObjPtr, "teamId", rcsSystem.game.player.team_id);
        cJSON_AddNumberToObject(dataObjPtr, "roomId", rcsSystem.game.player.room_id);
        cJSON_AddNumberToObject(dataObjPtr, "gameId", rcsSystem.game.record_id);
        cJSON_AddNumberToObject(dataObjPtr, "hp", rcsSystem.game.player.hp);
        cJSON_AddNumberToObject(dataObjPtr, "bullets", rcsSystem.game.player.bullet_nums);
        cJSON_AddNumberToObject(dataObjPtr, "atc", rcsSystem.game.player.damage);
        break;
    }
    case START_GAME_NET_UP:
    {
        cJSON_AddNumberToObject(dataObjPtr, "opt", (const int32_t)param[0]);
        break;
    }
    case ERROR_NET_UP:
    {
        cJSON_AddNumberToObject(dataObjPtr, "sourceType", (const int32_t)param[0]);
        cJSON_AddNumberToObject(dataObjPtr, "sourceDno", (const int32_t)rcsSystem.game.player.id);
        cJSON_AddNumberToObject(dataObjPtr, "cmd", (const int32_t)param[1]);
        break;
    }
    default:
        break;
    }

    char *dataStr = cJSON_Print(dataObjPtr);
    if (!dataStr) {
        cJSON_Delete(cjsonPtr);
        cJSON_Delete(dataObjPtr);
        ESP_LOGE(NET_TAG, "dataStr = cJSON_Print(dataObjPtr) == NULL");
        return NULL;
    }
    // ESP_LOGI(NET_TAG, "dataStr:%s", dataStr);
    cJSON_AddStringToObject(cjsonPtr, "data", dataStr);
    char *message = cJSON_Print(cjsonPtr);
    if (message != NULL)
    {
        *message_len = strlen((const char *)message);
        // ESP_LOGI(NET_TAG, "message_len:%d, %s", *message_len, message); 
    } else {
        ESP_LOGE(NET_TAG, "dataStr = cJSON_Print(dataObjPtr) == NULL");
    }
    cJSON_Delete(cjsonPtr);
    cJSON_Delete(dataObjPtr);
    free(dataStr);
    return message;
}
